package pl.dsp.dsp1.processing;

import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;

public class Radar {
	private ActionListener updateListener;
	Timer updateTimer, computeAndNotifyTimer;

	private Signal original, received, correlated;
	private double computed;

	private double samplingPeriod;
	private double T;

	private double t = 0;
	private double delay;
	private double signalSpeed;

	public Signal getOriginal() {
		return original;
	}

	public Signal getReceived() {
		return received;
	}

	public Signal getCorrelated() {
		return correlated;
	}

	public Radar(int bufferSize, double objectDistance, double signalSpeed,
			double T, double fp, double refreshTime) {
		this.samplingPeriod = 1 / fp;
		this.T = T;
		this.delay = 2 * objectDistance / signalSpeed;
		this.signalSpeed = signalSpeed;

		updateTimer = new Timer();
		updateTimer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				update();
			}
		}, (long) (samplingPeriod * 1000), (long) (samplingPeriod * 1000));

		computeAndNotifyTimer = new Timer();
		computeAndNotifyTimer.schedule(new TimerTask() {
			@Override
			public void run() {
				computeAndNotify();
			}
		}, (long) (refreshTime * 1000), (long) (refreshTime * 1000));

		original = new Signal(1, 1);
		received = new Signal(1, 1);
		for (int index = 0; index < bufferSize; index++) {
			original.add(new SimpleValue(0));
			received.add(new SimpleValue(0));
		}
	}

	private synchronized void update() {
		t += samplingPeriod;

		Generator g = GeneratorFactory.selectGenerator(
				GeneratorFactory.Source.SINE, 0);

		SignalValue value = new SimpleValue(0);
		value = value.add(g.at(t / T));
		value = value.substract(g.at(t / (T / 3)).multiply(new SimpleValue(0.5)));
		value = value.add(g.at(t / (T / 5)).multiply(new SimpleValue(0.25)));
		value = value.substract(g.at(t / (T / 6)).multiply(new SimpleValue(0.5)));

		original.add(value);
		original.remove(0);

		int delayedSample = original.size() - 1
				- (int) (delay / samplingPeriod);
		received.add(original.get(delayedSample));
		received.remove(0);
	}

	private synchronized void computeAndNotify() {
		correlated = received.correlate(original);
		double max = Double.MIN_VALUE;
		int position = 0;
		for (int index = correlated.size() / 2; index < correlated.size(); index++) {
			if (max < correlated.get(index).getValues().get(0)) {
				max = correlated.get(index).getValues().get(0);
				position = index;
			}
		}
		
		computed = (position - correlated.size() / 2) * samplingPeriod / 2.0 * signalSpeed;

		if (updateListener != null)
			updateListener.actionPerformed(null);
	}

	public void setUpdateListener(ActionListener listener) {
		this.updateListener = listener;
	}

	public void stop() {
		computeAndNotifyTimer.cancel();
		updateTimer.cancel();
	}

	public double getComputed() {
		return computed;
	}
}
